1. Introdução à Análise de Cluster

A Análise de Cluster (ou Agrupamento) é uma técnica de aprendizado não supervisionado que visa agrupar objetos semelhantes em grupos chamados clusters. O objetivo principal é maximizar a homogeneidade dentro dos grupos e a heterogeneidade entre os grupos. Na área da saúde, esta técnica tem diversas aplicações, como:

  • Identificação de padrões em dados de pacientes
  • Segmentação de perfis epidemiológicos
  • Agrupamento de hospitais por características de atendimento
  • Identificação de grupos de risco em doenças crônicas
  • Análise de comorbidades

Neste tutorial, aplicaremos a Análise de Cluster em um conjunto de dados relacionado à saúde para identificar perfis de pacientes com diabetes.

2. Carregamento de Pacotes e Dados

# Carregamento dos pacotes necessários
library(tidyverse)    # Manipulação de dados
library(cluster)      # Algoritmos de clustering
library(factoextra)   # Visualização de clusters
library(NbClust)      # Determinação do número ideal de clusters
library(corrplot)     # Visualização de correlações
library(gridExtra)    # Organização de gráficos

2.1 Sobre o conjunto de dados

Utilizaremos o conjunto de dados “Pima Indians Diabetes”, que contém informações de 768 mulheres da população indígena Pima, com fatores de risco para diabetes. As variáveis incluem:

# Carregamento dos dados
url <- "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.csv"
diabetes <- read.csv(url, header = FALSE)

# Definição dos nomes das colunas
colnames(diabetes) <- c("Pregnancies", "Glucose", "BloodPressure", 
                         "SkinThickness", "Insulin", "BMI", 
                         "DiabetesPedigreeFunction", "Age", "Outcome")

# Visualização das primeiras linhas
head(diabetes)
##   Pregnancies Glucose BloodPressure SkinThickness Insulin  BMI
## 1           6     148            72            35       0 33.6
## 2           1      85            66            29       0 26.6
## 3           8     183            64             0       0 23.3
## 4           1      89            66            23      94 28.1
## 5           0     137            40            35     168 43.1
## 6           5     116            74             0       0 25.6
##   DiabetesPedigreeFunction Age Outcome
## 1                    0.627  50       1
## 2                    0.351  31       0
## 3                    0.672  32       1
## 4                    0.167  21       0
## 5                    2.288  33       1
## 6                    0.201  30       0
# Informações sobre o dataset
str(diabetes)
## 'data.frame':    768 obs. of  9 variables:
##  $ Pregnancies             : int  6 1 8 1 0 5 3 10 2 8 ...
##  $ Glucose                 : int  148 85 183 89 137 116 78 115 197 125 ...
##  $ BloodPressure           : int  72 66 64 66 40 74 50 0 70 96 ...
##  $ SkinThickness           : int  35 29 0 23 35 0 32 0 45 0 ...
##  $ Insulin                 : int  0 0 0 94 168 0 88 0 543 0 ...
##  $ BMI                     : num  33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 0 ...
##  $ DiabetesPedigreeFunction: num  0.627 0.351 0.672 0.167 2.288 ...
##  $ Age                     : int  50 31 32 21 33 30 26 29 53 54 ...
##  $ Outcome                 : int  1 0 1 0 1 0 1 0 1 1 ...
  • Pregnancies: Número de gestações
  • Glucose: Concentração de glicose plasmática após 2 horas em um teste oral de tolerância à glicose
  • BloodPressure: Pressão arterial diastólica (mm Hg)
  • SkinThickness: Espessura da dobra cutânea do tríceps (mm)
  • Insulin: Insulina sérica de 2 horas (mu U/ml)
  • BMI: Índice de massa corporal (peso em kg/(altura em m)²)
  • DiabetesPedigreeFunction: Função de pedigree de diabetes (histórico familiar)
  • Age: Idade (anos)
  • Outcome: Variável de resultado (0 = sem diabetes, 1 = diabetes)

3. Pré-processamento dos Dados

Antes de aplicar as técnicas de clustering, precisamos realizar algumas etapas de pré-processamento:

# Verificando valores ausentes (zeros em algumas variáveis são biologicamente impossíveis)
diabetes_clean <- diabetes %>%
  mutate(
    Glucose = ifelse(Glucose == 0, NA, Glucose),
    BloodPressure = ifelse(BloodPressure == 0, NA, BloodPressure),
    SkinThickness = ifelse(SkinThickness == 0, NA, SkinThickness),
    Insulin = ifelse(Insulin == 0, NA, Insulin),
    BMI = ifelse(BMI == 0, NA, BMI)
  )

# Resumo estatístico
summary(diabetes_clean)
##   Pregnancies        Glucose      BloodPressure    SkinThickness  
##  Min.   : 0.000   Min.   : 44.0   Min.   : 24.00   Min.   : 7.00  
##  1st Qu.: 1.000   1st Qu.: 99.0   1st Qu.: 64.00   1st Qu.:22.00  
##  Median : 3.000   Median :117.0   Median : 72.00   Median :29.00  
##  Mean   : 3.845   Mean   :121.7   Mean   : 72.41   Mean   :29.15  
##  3rd Qu.: 6.000   3rd Qu.:141.0   3rd Qu.: 80.00   3rd Qu.:36.00  
##  Max.   :17.000   Max.   :199.0   Max.   :122.00   Max.   :99.00  
##                   NA's   :5       NA's   :35       NA's   :227    
##     Insulin            BMI        DiabetesPedigreeFunction      Age       
##  Min.   : 14.00   Min.   :18.20   Min.   :0.0780           Min.   :21.00  
##  1st Qu.: 76.25   1st Qu.:27.50   1st Qu.:0.2437           1st Qu.:24.00  
##  Median :125.00   Median :32.30   Median :0.3725           Median :29.00  
##  Mean   :155.55   Mean   :32.46   Mean   :0.4719           Mean   :33.24  
##  3rd Qu.:190.00   3rd Qu.:36.60   3rd Qu.:0.6262           3rd Qu.:41.00  
##  Max.   :846.00   Max.   :67.10   Max.   :2.4200           Max.   :81.00  
##  NA's   :374      NA's   :11                                              
##     Outcome     
##  Min.   :0.000  
##  1st Qu.:0.000  
##  Median :0.000  
##  Mean   :0.349  
##  3rd Qu.:1.000  
##  Max.   :1.000  
## 
# Imputação de valores ausentes pela mediana (abordagem simples)
diabetes_imputed <- diabetes_clean %>%
  mutate(
    Glucose = ifelse(is.na(Glucose), median(Glucose, na.rm = TRUE), Glucose),
    BloodPressure = ifelse(is.na(BloodPressure), median(BloodPressure, na.rm = TRUE), BloodPressure),
    SkinThickness = ifelse(is.na(SkinThickness), median(SkinThickness, na.rm = TRUE), SkinThickness),
    Insulin = ifelse(is.na(Insulin), median(Insulin, na.rm = TRUE), Insulin),
    BMI = ifelse(is.na(BMI), median(BMI, na.rm = TRUE), BMI)
  )

# Verificando após imputação
summary(diabetes_imputed)
##   Pregnancies        Glucose       BloodPressure    SkinThickness  
##  Min.   : 0.000   Min.   : 44.00   Min.   : 24.00   Min.   : 7.00  
##  1st Qu.: 1.000   1st Qu.: 99.75   1st Qu.: 64.00   1st Qu.:25.00  
##  Median : 3.000   Median :117.00   Median : 72.00   Median :29.00  
##  Mean   : 3.845   Mean   :121.66   Mean   : 72.39   Mean   :29.11  
##  3rd Qu.: 6.000   3rd Qu.:140.25   3rd Qu.: 80.00   3rd Qu.:32.00  
##  Max.   :17.000   Max.   :199.00   Max.   :122.00   Max.   :99.00  
##     Insulin           BMI        DiabetesPedigreeFunction      Age       
##  Min.   : 14.0   Min.   :18.20   Min.   :0.0780           Min.   :21.00  
##  1st Qu.:121.5   1st Qu.:27.50   1st Qu.:0.2437           1st Qu.:24.00  
##  Median :125.0   Median :32.30   Median :0.3725           Median :29.00  
##  Mean   :140.7   Mean   :32.46   Mean   :0.4719           Mean   :33.24  
##  3rd Qu.:127.2   3rd Qu.:36.60   3rd Qu.:0.6262           3rd Qu.:41.00  
##  Max.   :846.0   Max.   :67.10   Max.   :2.4200           Max.   :81.00  
##     Outcome     
##  Min.   :0.000  
##  1st Qu.:0.000  
##  Median :0.000  
##  Mean   :0.349  
##  3rd Qu.:1.000  
##  Max.   :1.000

3.1 Análise exploratória e correlações

# Matriz de correlação
cor_matrix <- cor(diabetes_imputed[, 1:8])
corrplot(cor_matrix, method = "circle", type = "upper", 
         tl.col = "black", tl.srt = 45)

# Distribuição das variáveis
p1 <- ggplot(diabetes_imputed, aes(x = Glucose)) + 
  geom_histogram(fill = "steelblue", bins = 30) + 
  theme_minimal() + labs(title = "Distribuição da Glucose")

p2 <- ggplot(diabetes_imputed, aes(x = BMI)) + 
  geom_histogram(fill = "steelblue", bins = 30) + 
  theme_minimal() + labs(title = "Distribuição do IMC")

p3 <- ggplot(diabetes_imputed, aes(x = Age)) + 
  geom_histogram(fill = "steelblue", bins = 30) + 
  theme_minimal() + labs(title = "Distribuição da Idade")

p4 <- ggplot(diabetes_imputed, aes(x = Insulin)) + 
  geom_histogram(fill = "steelblue", bins = 30) + 
  theme_minimal() + labs(title = "Distribuição da Insulina")

grid.arrange(p1, p2, p3, p4, ncol = 2)

# Relação entre variáveis por status de diabetes
ggplot(diabetes_imputed, aes(x = BMI, y = Glucose, color = factor(Outcome))) + 
  geom_point(alpha = 0.6) + 
  scale_color_manual(values = c("blue", "red"), 
                     labels = c("Sem Diabetes", "Com Diabetes"),
                     name = "Diagnóstico") +
  theme_minimal() +
  labs(title = "Relação entre IMC e Glucose por status de diabetes")

# Matriz de Correlação

  • Há correlação positiva significativa entre Glucose e Age (idade e glicose sanguínea)
  • Existe correlação moderada entre BMI (IMC) e SkinThickness (espessura cutânea)
  • A Insulin (insulina) está correlacionada com Glucose e SkinThickness
  • Estas correlações indicam relações biológicas esperadas, como a relação entre obesidade (IMC) e níveis de insulina

Histogramas

  • A distribuição de Glucose tem forma aproximadamente normal com leve assimetria à direita
  • O IMC (BMI) tem distribuição próxima da normal com média em torno de 32
  • A distribuição da idade (Age) é assimétrica positiva, com maior concentração de pacientes jovens
  • A insulina (Insulin) apresenta uma distribuição muito assimétrica com muitos valores próximos à mediana

3.2 Preparação para clustering

Vamos selecionar as variáveis relevantes, excluir a variável alvo (Outcome) e normalizar os dados:

# Selecionando variáveis para clustering
diabetes_cluster <- diabetes_imputed %>%
  select(-Outcome) # Removendo a variável alvo para não influenciar o clustering

# Normalização dos dados (importante para algoritmos baseados em distância)
diabetes_scaled <- scale(diabetes_cluster)
summary(diabetes_scaled)
##   Pregnancies         Glucose        BloodPressure      SkinThickness     
##  Min.   :-1.1411   Min.   :-2.5513   Min.   :-4.00001   Min.   :-2.51479  
##  1st Qu.:-0.8443   1st Qu.:-0.7197   1st Qu.:-0.69331   1st Qu.:-0.46729  
##  Median :-0.2508   Median :-0.1530   Median :-0.03197   Median :-0.01229  
##  Mean   : 0.0000   Mean   : 0.0000   Mean   : 0.00000   Mean   : 0.00000  
##  3rd Qu.: 0.6395   3rd Qu.: 0.6109   3rd Qu.: 0.62937   3rd Qu.: 0.32896  
##  Max.   : 3.9040   Max.   : 2.5410   Max.   : 4.10141   Max.   : 7.95020  
##     Insulin             BMI           DiabetesPedigreeFunction
##  Min.   :-1.4664   Min.   :-2.07343   Min.   :-1.1888         
##  1st Qu.:-0.2219   1st Qu.:-0.72074   1st Qu.:-0.6885         
##  Median :-0.1814   Median :-0.02258   Median :-0.2999         
##  Mean   : 0.0000   Mean   : 0.00000   Mean   : 0.0000         
##  3rd Qu.:-0.1554   3rd Qu.: 0.60286   3rd Qu.: 0.4659         
##  Max.   : 8.1651   Max.   : 5.03911   Max.   : 5.8797         
##       Age         
##  Min.   :-1.0409  
##  1st Qu.:-0.7858  
##  Median :-0.3606  
##  Mean   : 0.0000  
##  3rd Qu.: 0.6598  
##  Max.   : 4.0611

4. Análise de Cluster Hierárquico

4.1 Determinação do número ideal de clusters

# Método do cotovelo
fviz_nbclust(diabetes_scaled, kmeans, method = "wss") +
  geom_vline(xintercept = 3, linetype = 2) +
  labs(title = "Método do Cotovelo")

# Método da silhueta
fviz_nbclust(diabetes_scaled, kmeans, method = "silhouette") +
  labs(title = "Método da Silhueta")

# Abordagem estatística (Gap statistic)
set.seed(123)
gap_stat <- clusGap(diabetes_scaled, FUN = kmeans, nstart = 25,
                    K.max = 10, B = 50)
fviz_gap_stat(gap_stat) +
  labs(title = "Estatística Gap")

  • Método do Cotovelo: O gráfico mostra uma inflexão (“cotovelo”) por volta de k=3, sugerindo três clusters como número ideal
  • Método da Silhueta: Apresenta valor máximo em k=2, mas também um valor alto em k=3
  • Estatística Gap: Sugere k=3 como número ótimo
  • A convergência de várias técnicas para k=3 fortalece a decisão de usar esse número de clusters

4.2 Dendrograma do clustering hierárquico

# Cálculo da matriz de distância
dist_matrix <- dist(diabetes_scaled, method = "euclidean")

# Clustering hierárquico
hc <- hclust(dist_matrix, method = "ward.D2")

# Visualização do dendrograma
fviz_dend(hc, k = 3, # Corte para 3 clusters
          cex = 0.5, 
          palette = "jco",
          rect = TRUE,
          rect_fill = TRUE,
          rect_border = "jco",
          labels_track_height = 0)  + 
  labs(title = "Dendrograma do Clustering Hierárquico")

# Criando grupos baseados no clustering hierárquico
hc_groups <- cutree(hc, k = 3)

O dendrograma mostra:

  • A estrutura hierárquica dos agrupamentos, com cores diferentes (azul, amarelo e cinza) para os três clusters
  • A altura das linhas indica a distância entre grupos, sendo que linhas mais altas representam maior dissimilaridade
  • A divisão clara em três grupos confirma visualmente a escolha de k=3

5. Análise de Cluster K-means

# Aplicando K-means com k=3
set.seed(123)
km <- kmeans(diabetes_scaled, centers = 3, nstart = 25)

# Visualização dos clusters
fviz_cluster(list(data = diabetes_scaled, cluster = km$cluster),
             palette = c("#00AFBB", "#FC4E07", "#E7B800"),
             ellipse.type = "convex",
             repel = TRUE,
             ggtheme = theme_minimal()) +
  labs(title = "Clusters pelo método K-means")

# Adicionando a informação de cluster ao dataset original
diabetes_results <- diabetes_imputed %>%
  mutate(cluster = factor(km$cluster),
         diabetes_status = factor(Outcome, labels = c("Sem Diabetes", "Com Diabetes")))

O gráfico de dispersão bidimensional mostra:

  • Três grupos distintos (azul, vermelho e amarelo) no espaço das duas primeiras componentes principais
  • Alguma sobreposição entre clusters, especialmente na região central
  • O cluster 1 (azul) mais concentrado, enquanto o cluster 2 (vermelho) tem maior dispersão

6. Interpretação dos Clusters

6.1 Características dos clusters

# Estatísticas descritivas por cluster
cluster_summary <- diabetes_results %>%
  group_by(cluster) %>%
  summarise(
    n = n(),
    Idade_media = mean(Age),
    IMC_medio = mean(BMI),
    Glucose_media = mean(Glucose),
    Pressao_media = mean(BloodPressure),
    Insulina_media = mean(Insulin),
    Perc_diabetes = mean(Outcome) * 100
  )

# Visualização das estatísticas
knitr::kable(cluster_summary, digits = 2,
             caption = "Características médias por cluster")
Características médias por cluster
cluster n Idade_media IMC_medio Glucose_media Pressao_media Insulina_media Perc_diabetes
1 337 25.94 28.56 106.53 66.75 113.33 13.06
2 248 46.04 32.81 130.79 78.42 139.63 51.61
3 183 29.33 39.16 137.14 74.60 192.44 52.46
# Distribuição de diabetes por cluster
ggplot(diabetes_results, aes(x = cluster, fill = diabetes_status)) +
  geom_bar(position = "fill") +
  scale_fill_manual(values = c("blue", "red")) +
  theme_minimal() +
  labs(title = "Proporção de casos de diabetes por cluster",
       y = "Proporção", x = "Cluster")

# Visualização das variáveis por cluster
p1 <- ggplot(diabetes_results, aes(x = cluster, y = Age, fill = cluster)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Idade por cluster")

p2 <- ggplot(diabetes_results, aes(x = cluster, y = Glucose, fill = cluster)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Glucose por cluster")

p3 <- ggplot(diabetes_results, aes(x = cluster, y = BMI, fill = cluster)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "IMC por cluster")

p4 <- ggplot(diabetes_results, aes(x = cluster, y = Insulin, fill = cluster)) +
  geom_boxplot() +
  theme_minimal() +
  labs(title = "Insulina por cluster")

grid.arrange(p1, p2, p3, p4, ncol = 2)

Idade: O cluster 2 (verde) tem idade média significativamente maior (cerca de 46 anos) Glucose: Os clusters 2 e 3 têm níveis médios de glicose mais elevados IMC: O cluster 3 (azul) apresenta IMC claramente mais alto (média ~40) Insulina: O cluster 3 também tem níveis de insulina mais elevados

6.2 Análise de componentes principais para visualização

# PCA para redução de dimensionalidade
pca_result <- prcomp(diabetes_scaled)
summary(pca_result)
## Importance of components:
##                           PC1    PC2    PC3    PC4     PC5     PC6     PC7
## Standard deviation     1.5110 1.2229 1.0684 0.9574 0.87685 0.73707 0.68443
## Proportion of Variance 0.2854 0.1870 0.1427 0.1146 0.09611 0.06791 0.05856
## Cumulative Proportion  0.2854 0.4723 0.6150 0.7296 0.82568 0.89359 0.95215
##                            PC8
## Standard deviation     0.61872
## Proportion of Variance 0.04785
## Cumulative Proportion  1.00000
# Visualização dos clusters no espaço PCA
fviz_pca_ind(pca_result,
             geom.ind = "point",
             col.ind = diabetes_results$cluster,
             palette = c("#00AFBB", "#FC4E07", "#E7B800"),
             addEllipses = TRUE,
             legend.title = "Cluster") +
  labs(title = "Clusters no espaço de componentes principais")

# Contribuição das variáveis para os componentes principais
fviz_pca_var(pca_result,
             col.var = "contrib",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE) +
  labs(title = "Contribuição das variáveis para os componentes principais")

Componentes Principais

Os três clusters em um espaço bidimensional após redução de dimensionalidade por PCA Elipses de confiança para cada cluster, mostrando o grau de dispersão Separação razoável entre clusters, mas com áreas de sobreposição

Variáveis para os Componentes Principais

As variáveis Age e Pregnancies têm maior contribuição para a dimensão vertical (PC2) Glucose, SkinThickness, Insulin e BMI contribuem mais para a dimensão horizontal (PC1) DiabetesPedigreeFunction tem contribuição significativa para ambas dimensões Isto ajuda a entender quais variáveis são mais importantes na formação dos clusters

7. Interpretação e Implicações para Tomada de Decisão

7.1 Perfil dos clusters identificados

Com base nas análises realizadas, podemos caracterizar os três clusters da seguinte forma:

# Criando rótulos descritivos para os clusters
cluster_labels <- c(
  "Cluster 1" = "Baixo Risco",
  "Cluster 2" = "Risco Intermediário",
  "Cluster 3" = "Alto Risco"
)

# Adicionando os rótulos ao dataset
diabetes_results <- diabetes_results %>%
  mutate(cluster_desc = recode(cluster, !!!cluster_labels))

# Tabela com perfil detalhado dos clusters
cluster_profile <- diabetes_results %>%
  group_by(cluster_desc) %>%
  summarise(
    Tamanho = n(),
    Percentual = n()/nrow(diabetes_results) * 100,
    Idade_media = mean(Age),
    IMC_medio = mean(BMI),
    Glucose_media = mean(Glucose),
    Insulina_media = mean(Insulin),
    Pressao_media = mean(BloodPressure),
    Historico_familiar = mean(DiabetesPedigreeFunction),
    Incidencia_diabetes = mean(Outcome) * 100
  )

knitr::kable(cluster_profile, digits = 1,
             caption = "Perfil detalhado dos clusters identificados")
Perfil detalhado dos clusters identificados
cluster_desc Tamanho Percentual Idade_media IMC_medio Glucose_media Insulina_media Pressao_media Historico_familiar Incidencia_diabetes
1 337 43.9 25.9 28.6 106.5 113.3 66.8 0.4 13.1
2 248 32.3 46.0 32.8 130.8 139.6 78.4 0.5 51.6
3 183 23.8 29.3 39.2 137.1 192.4 74.6 0.6 52.5

7.2 Interpretação dos clusters

Cluster 1 - Baixo Risco: Este grupo é caracterizado por pacientes mais jovens, com níveis normais de glicose, IMC mais baixo e menor incidência de diabetes. Representa indivíduos com menor risco metabólico e menor necessidade de intervenções imediatas.

Cluster 2 - Risco Intermediário: Este grupo inclui pacientes com idade intermediária, níveis de glicose e IMC moderadamente elevados. A incidência de diabetes é maior que no Cluster 1, sugerindo um grupo que requer monitoramento regular e intervenções preventivas.

Cluster 3 - Alto Risco: Este grupo é composto principalmente por pacientes mais velhos, com níveis elevados de glicose, IMC mais alto e maior incidência de diabetes. Representa um grupo prioritário para intervenções clínicas intensivas.

7.3 Implicações para a tomada de decisão clínica

A identificação destes clusters tem várias implicações para a gestão em saúde:

  1. Estratificação de risco: Os clusters permitem categorizar pacientes em diferentes níveis de risco, orientando a alocação de recursos de saúde.

  2. Personalização de intervenções:

    • Cluster 1 (Baixo Risco): Foco em prevenção primária e educação em saúde.
    • Cluster 2 (Risco Intermediário): Monitoramento regular, modificações no estilo de vida e possível intervenção farmacológica preventiva.
    • Cluster 3 (Alto Risco): Acompanhamento intensivo, tratamento agressivo dos fatores de risco e possível rastreamento de complicações.
  3. Otimização de recursos: Direcionamento de recursos mais intensivos para pacientes do Cluster 3, enquanto abordagens mais gerais podem ser suficientes para o Cluster 1.

  4. Criação de protocolos clínicos: Desenvolvimento de protocolos específicos para cada cluster, considerando suas características particulares.

  5. Predição de resultados: Uso dos perfis de cluster para estimar prognósticos e planejar intervenções preventivas.

# Visualização da distribuição dos clusters com tamanho proporcional ao número de casos
ggplot(diabetes_results, aes(x = cluster_desc, fill = diabetes_status)) +
  geom_bar() +
  scale_fill_manual(values = c("blue", "red")) +
  theme_minimal() +
  labs(title = "Distribuição de casos de diabetes por cluster",
       x = "Perfil do Cluster", y = "Número de pacientes",
       fill = "Status de Diabetes")

8. Validação dos Clusters

8.1 Avaliação da qualidade do agrupamento

# Silhueta média dos clusters
sil <- silhouette(km$cluster, dist_matrix)
fviz_silhouette(sil) +
  labs(title = "Gráfico de Silhueta dos Clusters")
##   cluster size ave.sil.width
## 1       1  337          0.32
## 2       2  248          0.15
## 3       3  183          0.04

# Estatísticas da silhueta
sil_stats <- summary(sil)

Gráfico de Silhueta

O cluster 1 tem a melhor silhueta média (0.32), indicando boa coesão Os clusters 2 e 3 têm valores mais baixos (0.15 e 0.04), sugerindo maior heterogeneidade A linha tracejada horizontal indica a silhueta média global (~0.22)

8.2 Validação com relação ao desfecho clínico (diabetes)

# Tabela de contingência entre clusters e status de diabetes
contingency_table <- table(Cluster = diabetes_results$cluster, 
                           Diabetes = diabetes_results$diabetes_status)
knitr::kable(contingency_table, 
             caption = "Distribuição de casos de diabetes por cluster")
Distribuição de casos de diabetes por cluster
Sem Diabetes Com Diabetes
293 44
120 128
87 96
# Teste qui-quadrado para verificar associação
chisq.test(contingency_table)
## 
##  Pearson's Chi-squared test
## 
## data:  contingency_table
## X-squared = 126.1, df = 2, p-value < 2.2e-16

Cluster 1 - Baixo Risco (43,9% dos pacientes):

Pacientes jovens (média 25,9 anos) IMC normal a levemente elevado (28,6) Glicose média mais baixa (106,5) Apenas 13% têm diabetes Pressão arterial média mais baixa (66,8)

Cluster 2 - Risco Intermediário (32,3% dos pacientes):

Pacientes mais velhos (média 46 anos) IMC moderadamente elevado (32,8) Níveis de glicose elevados (130,8) 51,6% têm diabetes Pressão arterial mais alta (78,4)

Cluster 3 - Alto Risco (23,8% dos pacientes):

Idade intermediária (média 29,3 anos) IMC muito elevado (39,2) - obesidade significativa Níveis de glicose mais elevados (137,1) 52,5% têm diabetes Níveis de insulina mais altos (192,4)

Teste de associação com diabetes

O teste qui-quadrado (χ² = 126.1, p < 0.0001) confirma que existe associação estatisticamente significativa entre os clusters identificados e o diagnóstico de diabetes, validando a relevância clínica dos grupos.

9. Conclusões e Próximos Passos

A análise de cluster aplicada a esta base de dados permitiu identificar três perfis distintos de pacientes, com diferentes níveis de risco para diabetes. Esta estratificação pode ser extremamente útil para a gestão em saúde, permitindo:

  1. Otimização de recursos: Ao identificar grupos de alto risco, os recursos de saúde podem ser direcionados de forma mais eficiente.

  2. Medicina personalizada: A partir da compreensão dos perfis, é possível desenvolver abordagens personalizadas para cada grupo.

  3. Prevenção direcionada: Estratégias preventivas específicas podem ser implementadas para cada cluster.

  4. Monitoramento inteligente: A identificação dos clusters permite estabelecer protocolos de acompanhamento com frequências diferentes para cada grupo.

As análises sugerem estratégias diferenciadas para cada grupo:

Para o Cluster 1 (Baixo Risco):

Foco em prevenção primária e educação em saúde Monitoramento menos frequente Intervenções de baixo custo focadas em manutenção da saúde

#Para o Cluster 2 (Risco Intermediário): Monitoramento regular Modificações no estilo de vida mais intensivas Possível intervenção farmacológica preventiva Atenção especial à idade mais avançada

Para o Cluster 3 (Alto Risco):

Acompanhamento intensivo Tratamento agressivo dos fatores de risco, especialmente obesidade Rastreamento de complicações Intervenções nutricionais e metabólicas específicas

Esta estratificação permite direcionar recursos de forma mais eficiente e personalizar o cuidado, concentrando esforços mais intensivos nos grupos de maior risco. Os resultados também mostram que a idade elevada (Cluster 2) e a obesidade significativa (Cluster 3) representam dois caminhos diferentes para o desenvolvimento de diabetes, o que sugere abordagens preventivas e terapêuticas distintas para cada grupo. A análise demonstra o potencial da técnica de clustering para auxiliar decisões clínicas e de gestão em saúde, identificando padrões que poderiam não ser evidentes ao analisar cada variável isoladamente.

9.1 Limitações da análise

  • A base de dados é relativamente pequena e específica para uma população (mulheres indígenas Pima).
  • A imputação de dados ausentes pela mediana é uma abordagem simples, que poderia ser refinada.
  • Outras técnicas de clustering poderiam ser exploradas e comparadas (DBSCAN, clustering espectral, etc.).

9.2 Próximos passos

  1. Validar os clusters em uma amostra independente.
  2. Desenvolver um modelo preditivo para classificar novos pacientes nos clusters identificados.
  3. Implementar e avaliar intervenções específicas para cada cluster.
  4. Refinar a análise incorporando dados longitudinais para avaliar a progressão dos pacientes entre clusters ao longo do tempo.
# Visualização final tridimensional dos clusters
plotly::plot_ly(
  x = pca_result$x[,1],
  y = pca_result$x[,2],
  z = pca_result$x[,3],
  type = "scatter3d",
  mode = "markers",
  color = factor(diabetes_results$cluster),
  colors = c("#00AFBB", "#FC4E07", "#E7B800"),
  marker = list(size = 5)
) %>%
  plotly::layout(
    title = "Visualização 3D dos clusters (PCA)",
    scene = list(
      xaxis = list(title = "PC1"),
      yaxis = list(title = "PC2"),
      zaxis = list(title = "PC3")
    )
  )

10. Referências

  1. Everitt, B. S., Landau, S., Leese, M., & Stahl, D. (2011). Cluster Analysis. Wiley.

  2. Kaufman, L., & Rousseeuw, P. J. (2009). Finding Groups in Data: An Introduction to Cluster Analysis. Wiley.

  3. Smith, J. W., Everhart, J. E., Dickson, W. C., Knowler, W. C., & Johannes, R. S. (1988). Using the ADAP learning algorithm to forecast the onset of diabetes mellitus. Proceedings of the Annual Symposium on Computer Application in Medical Care, 261-265.

  4. Zhang, X., Gregg, E. W., Williamson, D. F., et al. (2010). A1C level and future risk of diabetes: a systematic review. Diabetes Care, 33(7), 1665-1673.

  5. Hennig, C., Meila, M., Murtagh, F., & Rocci, R. (Eds.). (2015). Handbook of Cluster Analysis. CRC Press.